# -*- coding: utf-8 -*-
import os.path
import pickle
import codecs
import urllib2
import os
import socket

from kivy.core.window import Window
from kivy.lang import Builder
from kivy.logger import Logger

from model.gamestate import GameState, Phase
from model.syssettings import SysSettings
from model.json_rounds_creater import JsonRoundsCreater
from ui.platform_adapter import PlatformAdapter
from constants import HOST
from constants import STATISTIC_COUNT
from constants import EXPORT_PROTOCOL_VERSION

JSON_EXT = ".json"
PKL_EXT = ".pkl"
GAME_PREFIX = EXPORT_PROTOCOL_VERSION + "_game"
STATISTIC_DIR = "statistics"


def _stat_files_list():
    return [file_name[:-len(JSON_EXT)]
            for file_name in os.listdir(STATISTIC_DIR)
            if file_name.endswith(JSON_EXT)]


def _full_json_filename(fname):
    return os.path.join(STATISTIC_DIR, fname + JSON_EXT)


def _json_by_filename(fname):
    with codecs.open(fname, encoding='utf-8', mode='r') as f:
        return f.read()


def _creation_time(stat_file):
    return int(os.stat(_full_json_filename(stat_file)).st_ctime)


def _parse_id_from_filename(fname):
    return int(fname[len(GAME_PREFIX):])


def _parse_version_from_filename(fname):
    return fname[:len(EXPORT_PROTOCOL_VERSION)]


def _old_json_file_count():
    return len([file_name for file_name in os.listdir(STATISTIC_DIR)
                if file_name.endswith(JSON_EXT + 'old')])


def _try_to_send_old_stat(json_sender):
    for fname in _stat_files_list():
        json_file = _full_json_filename(fname)

        if _parse_version_from_filename(fname) == EXPORT_PROTOCOL_VERSION:
            try:
                json_sender.dump_to_url(
                    HOST + '/create_game_history',
                    _json_by_filename(json_file))
                Logger.debug("%s uploaded to server" % fname)
            except:
                Logger.debug("Unable to upload results %s" % fname)
                break

        try:
            #os.unlink(json_file)
            os.rename(json_file, _full_json_filename(
                fname + '_' + str(_old_json_file_count())) + 'old')
        except:
            pass


class BasePresenter(object):
    def request_app_close(self):
        pass

    def close_app(self):
        self.game_state.is_paused = True
        Logger.debug('Save game_state: ')
        Logger.debug('To file: ' + 'data/pickled_gamestate.pkl')
        Logger.debug('Current phase: ' + str(self.game_state.phase))

        pickled_file = open('data/pickled_gamestate.pkl', 'wb')

        pickle.dump(self.game_state, pickled_file)
        pickled_file.close()
        return True

    def resume_app(self):
        if os.path.exists('data/pickled_gamestate.pkl'):
            Logger.debug('Load game_state from file: ' +
                         'data/pickled_gamestate.pkl')
            pickled_file = open('data/pickled_gamestate.pkl', 'rb')

            self.game_state = pickle.load(pickled_file)
            Logger.debug('game_state loaded: ')
            Logger.debug('phase in loaded game_state: ' +
                         str(self.game_state.phase))
            pickled_file.close()
            if self.game_state.phase in [Phase.GUESS_WORD, Phase.BEFORE_ROUND]:
                self.change_phase(Phase.FROM_TO)
            self.change_phase(self.game_state.phase)

    def save_statistics(self):
        _try_to_send_old_stat(JsonRoundsCreater())
        self.game_state.is_paused = True
        files = sorted([(_creation_time(fname), fname)
                        for fname in _stat_files_list()])
        num = len(files)
        to_remove = num - STATISTIC_COUNT
        if num >= STATISTIC_COUNT:
            for i in range(to_remove):
                try:
                    os.remove(os.path.join(
                        STATISTIC_DIR,
                        files[i][1] + '.json'))
                except:
                    pass
        if len(files) != 0:
            time, file = files[-1]
            out_file_num = _parse_id_from_filename(file) + 1
        else:
            out_file_num = 0

        json_creater = JsonRoundsCreater()
        json_string = json_creater.create_json_rounds(
            self.game_state.rounds, self.game_state.hat,
            self.game_state.settings, self.game_state.remote_id,
            self.game_state.players.players_select_strategy,
            self.game_state.pin_code)

        try:
            json_creater.dump_to_url(HOST + '/create_game_history',
                                     json_string)
            with codecs.open(os.path.join('statistics',
                                          GAME_PREFIX + str(out_file_num) +
                                          '_' + str(_old_json_file_count()) +
                                          '.jsonold'),
                             encoding='utf-8', mode='w') as f:
                f.write(json_string)
            Logger.debug("This results uploaded")
        except urllib2.URLError:
            Logger.debug("Unable to upload this results")
            with codecs.open(os.path.join('statistics', GAME_PREFIX +
                                          str(out_file_num) + '.json'),
                             encoding='utf-8', mode='w') as f:
                f.write(json_string)
        except socket.timeout:
            Logger.debug("Unable to upload this results")
            with codecs.open(os.path.join('statistics', GAME_PREFIX +
                                          str(out_file_num) + '.json'),
                             encoding='utf-8', mode='w') as f:
                f.write(json_string)


class Presenter(BasePresenter):
    orientation_change_enabled = True
    registered_kvs = {}

    def __init__(self, main_view, path):
        _try_to_send_old_stat(JsonRoundsCreater())
        self.path = path
        self.adapter = PlatformAdapter.get_adapter()
        self.widgets = dict()
        self.main_view = main_view
        self.game_state = GameState(None, None, None,
                                    None, None, None, None)

        Builder.load_file(os.path.join(os.path.dirname(__file__),
                                       'hatwidget.kv'))
        Builder.load_file(os.path.join(os.path.dirname(__file__),
                                       'resultsgeneral.kv'))

        self.settings = SysSettings(self.path + '/data/config.ini')

    def change_phase(self, phase):
        """ Changes phase of application



        Args:

        phase: (Phase)



        """
        self.adapter.hide_keyboard()
        self.main_view.content.clear_widgets()
        self.game_state.phase = phase
        w = self.widgets[phase](self.game_state, self)
        self.main_view.content.add_widget(w)

        self.rotate()

    def orientation(self):
        return Window.rotation

    def register_view(self, phase, widget_class, widget_names):
        """ Adds screen to presenter's dictionary



        Args:

        phase: (Phase)

        widget: (class)

        widget_name: (String)



        """
        if phase in self.widgets:
            raise Exception('Duplicate widget for phase %s' % phase)
        if widget_names is not None:
            for widget_name in widget_names:
                if widget_name in self.registered_kvs:
                    raise Exception('Trying to load duplicate %s.kv' %
                                    widget_name)
                self.registered_kvs[widget_name] = phase
                Builder.load_file(os.path.join(os.path.dirname(__file__),
                                               widget_name + '.kv'))
        self.widgets[phase] = widget_class

    def restart(self):
        self.save_statistics()
        self.game_state.clear()
        self.change_phase(Phase.WELCOME)

    def rotate(self):
        phase = self.game_state.phase
        if phase in [Phase.FROM_TO, Phase.BEFORE_ROUND,
                     Phase.GUESS_WORD, Phase.RESULTS_OF_ONE_PAIR]:
            orientation = self.settings.graphics.horizontal_orientation
        else:
            orientation = self.settings.graphics.vertical_orientation
        self.set_orientation(orientation)

    def set_orientation(self, orietation):
        if self.orientation_change_enabled:
            Window.rotation = orietation

    def update(self):
        for widget in self.main_view.content.children:
            widget.update()
